package framework.system;

import framework.fault.IFaultTolerantPeer;
import framework.grid.DummyNodePeer;
import framework.grid.GridAlgorithm;
import framework.grid.NodePeer;
import framework.util.PeerEdge;
import framework.util.PeerNode;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;


public class BackEndImpl extends UnicastRemoteObject implements BackEnd {
	private NodePeer dummyRoot = new DummyNodePeer(); {
		this.dummyRoot.getMetaData().setNode(
				new PeerNode(GridAlgorithm.ROOT_PATH, GridAlgorithm.ROOT_PATH, this.dummyRoot));
	}
	//TODO replace with RingBuffer
	private LinkedList<IFaultTolerantPeer> isolated = new LinkedList<IFaultTolerantPeer>();
	private LinkedList<IFaultTolerantPeer> missingLeft = new LinkedList<IFaultTolerantPeer>();
	private LinkedList<IFaultTolerantPeer> missingRight = new LinkedList<IFaultTolerantPeer>();
	
	public BackEndImpl() throws RemoteException {
		super();
	}
	
	
	
	@Override
	public synchronized void joinGrid(NodePeer peer) throws RemoteException {
		PeerEdge ref = this.dummyRoot.getMetaData().getRef(0);
		if (ref == null) {
			PeerEdge toPeer = 
				new PeerEdge(GridAlgorithm.EMPTY_PATH, peer.getMetaData().getNode());
			this.dummyRoot.getMetaData().setRef(0, toPeer);
			
			PeerEdge toRoot = 
				new PeerEdge(GridAlgorithm.ROOT_PATH, this.dummyRoot.getMetaData().getNode());
			peer.getMetaData().setRef(0, toRoot);
		} else {
			NodePeer realRoot = this.dummyRoot.getMetaData().getRef(0).getTargetNode().getPeer();
			realRoot.join(peer);
		}
	}
	@Override
	public synchronized void leaveGrid(NodePeer peer) throws RemoteException {
		NodePeer realRoot = this.dummyRoot.getMetaData().getRef(0).getTargetNode().getPeer();
		realRoot.leave(peer);
	}
	
	
	
	
	@Override
	public synchronized String[] get(String key) throws RemoteException {
		NodePeer realRoot = this.dummyRoot.getMetaData().getRef(0).getTargetNode().getPeer();
		return realRoot.get(key);
	}
	@Override
	public synchronized void put(String key, String value) throws RemoteException {
		NodePeer realRoot = this.dummyRoot.getMetaData().getRef(0).getTargetNode().getPeer();
		realRoot.put(key, value);
	}
	@Override
	public synchronized String[] remove(String key) throws RemoteException {
		NodePeer realRoot = this.dummyRoot.getMetaData().getRef(0).getTargetNode().getPeer();
		return realRoot.remove(key);
	}

	
	


	@Override
	public IFaultTolerantPeer[] publishIsolated(IFaultTolerantPeer newPeer)
			throws RemoteException {
		IFaultTolerantPeer[] out = new IFaultTolerantPeer[this.isolated.size()];
		this.isolated.toArray(out);
		this.isolated.addFirst(newPeer);
		return out;
	}

	@Override
	public IFaultTolerantPeer[] publishMissingLeft(IFaultTolerantPeer missingLeft)
			throws RemoteException {
		IFaultTolerantPeer[] out = new IFaultTolerantPeer[this.missingRight.size()];
		this.missingRight.toArray(out);
		this.missingLeft.addFirst(missingLeft);
		return out;
	}

	@Override
	public IFaultTolerantPeer[] publishMissingRight(IFaultTolerantPeer missingRight)
			throws RemoteException {
		IFaultTolerantPeer[] out = new IFaultTolerantPeer[this.missingLeft.size()];
		this.missingLeft.toArray(out);
		this.missingRight.addFirst(missingRight);
		return out;
	}
	


}
